package com.genreate.domain.export;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.db.Entity;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 导出工具类
 *
 * @author Administrator
 * @date 2023/08/17
 */
public class PoiUtils {
    /**
     * 默认行高
     */
    public static final int DEFAULT_ROW_HEIGHT = 36;

    /**
     * 默认图片行高
     */
    public static final int DEFAULT_IMG_ROW_HEIGHT = 150;

    /**
     * 默认列宽
     */
    public static final int DEFAULT_COL_WIDTH = 15;

    /**
     * 默认图片宽度
     */
    public static final int DEFAULT_IMG_COL_WIDTH = 40;

    /**
     * 默认字体大小
     */
    public static final int DEFAULT_FONT_SIZE = 11;

    /**
     * 标题字体大小
     */
    public static final int HEADER_FONT_SIZE = 14;

    /**
     * 序号
     */
    public static final String SERIAL_NUMBER = "serialNumber";

    /**
     * 导出excel
     * 格式：
     * 第一行字段标题（自动添加序号）
     * 下面是数据
     *
     * @param datas      数据
     * @param keyDatas   键
     * @param titleDatas 标题
     * @return {@link ExcelWriter}
     */
    public static ExcelWriter exportExcel(List<Entity> datas, List<String> keyDatas, List<String> titleDatas) {
        List<String> keys = new ArrayList<>(keyDatas);
        keys.add(0, SERIAL_NUMBER);
        List<String> title = new ArrayList<>(titleDatas);
        title.add(0, "序号");
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter();
        //首行样式
        CellStyle headerStyle = PoiUtils.headerStyle(writer);
        //内容样式
        CellStyle contentStyle = PoiUtils.contentStyle(writer);
        //设置列宽，首行样式，数据
        for (int i = 0; i < title.size(); i++) {
            String bt = title.get(i);
            if (i == 0) {
                writer.setColumnWidth(i, 8);
            } else {
                writer.setColumnWidth(i, PoiUtils.DEFAULT_COL_WIDTH);
            }
            writer.writeCellValue(i, 0, bt);
            writer.setStyle(headerStyle, i, 0);
        }
        writer.setRowHeight(0, PoiUtils.DEFAULT_ROW_HEIGHT);
        //数据行
        int dataRow = 1;
        for (int i = 0; i < datas.size(); i++) {
            Entity e = datas.get(i);
            e.set(SERIAL_NUMBER, i + 1);
            for (int j = 0; j < keys.size(); j++) {
                writer.writeCellValue(j, dataRow, changeExcelValue(e.get(keys.get(j))));
                writer.setStyle(contentStyle, j, dataRow);
            }
            writer.setRowHeight(dataRow, DEFAULT_ROW_HEIGHT);
            dataRow++;
        }
        return writer;
    }

    /**
     * 导出excel
     * 格式：
     * 第一行题目标题（自动添加序号）
     * 下面是数据
     *
     * @param datas      数据
     * @param keyDatas   键
     * @param titleDatas 标题
     * @param content    首行标题内容
     * @return {@link ExcelWriter}
     */
    public static ExcelWriter exportExcel(List<Entity> datas, List<String> keyDatas, List<String> titleDatas, String content) {
        List<String> keys = new ArrayList<>(keyDatas);
        keys.add(0, SERIAL_NUMBER);
        List<String> title = new ArrayList<>(titleDatas);
        title.add(0, "序号");
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter();
        //首行样式
        CellStyle headerStyle = PoiUtils.headerStyle(writer);
        //内容样式
        CellStyle contentStyle = PoiUtils.contentStyle(writer);
        //设置列宽，首行样式，数据
        for (int i = 0; i < title.size(); i++) {
            String bt = title.get(i);
            if (i == 0) {
                writer.setColumnWidth(i, 8);
            } else {
                writer.setColumnWidth(i, PoiUtils.DEFAULT_COL_WIDTH);
            }
            writer.writeCellValue(i, 1, bt);
            writer.setStyle(headerStyle, i, 1);
        }
        writer.merge(0, 0, 0, title.size() - 1, content, headerStyle);
        writer.setRowHeight(0, PoiUtils.DEFAULT_ROW_HEIGHT);
        writer.setRowHeight(1, PoiUtils.DEFAULT_ROW_HEIGHT);
        //数据行
        int dataRow = 2;
        for (int i = 0; i < datas.size(); i++) {
            Entity e = datas.get(i);
            e.set(SERIAL_NUMBER, i + 1);
            for (int j = 0; j < keys.size(); j++) {
                writer.writeCellValue(j, dataRow, changeExcelValue(e.get(keys.get(j))));
                writer.setStyle(contentStyle, j, dataRow);
            }
            writer.setRowHeight(dataRow, DEFAULT_ROW_HEIGHT);
            dataRow++;
        }
        return writer;
    }

    /**
     * header样式
     *
     * @param writer 工作簿
     * @return {@link CellStyle}
     */
    public static CellStyle headerStyle(ExcelWriter writer) {
        return headerStyle(writer.createCellStyle(), writer.createFont(), HEADER_FONT_SIZE);
    }

    /**
     * 内容样式
     *
     * @param writer 作家
     * @return {@link CellStyle}
     */
    public static CellStyle contentStyle(ExcelWriter writer) {
        return contentStyle(writer.createCellStyle(), writer.createFont(), DEFAULT_FONT_SIZE);
    }

    /**
     * 内容样式
     *
     * @param cellStyle 单元格样式
     * @param font      字体
     * @param fontSize  字体大小
     * @return {@link CellStyle}
     */
    public static CellStyle contentStyle(CellStyle cellStyle, Font font, int fontSize) {
        font.setFontHeightInPoints((short) fontSize);
        font.setFontName("微软雅黑");
        cellStyle.setFont(font);
        czSpCenter(cellStyle);
        return border(cellStyle);
    }

    /**
     * 设置全边框居中的样式
     *
     * @param style  需要修改的样式对象
     * @param font   字体
     * @param isWrap 是否自动换行
     * @return {@link XSSFCellStyle}
     */
    public static XSSFCellStyle setXSSFCellStyle(XSSFCellStyle style, XSSFFont font, boolean isWrap) {
        //是否自动换行
        style.setWrapText(isWrap);
        //中心对齐单元格内容
        style.setAlignment(HorizontalAlignment.CENTER);
        //对齐单元格内容垂直居中
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        //下边框
        style.setBorderBottom(BorderStyle.THIN);
        //左边框
        style.setBorderLeft(BorderStyle.THIN);
        //上边框
        style.setBorderTop(BorderStyle.THIN);
        //右边框
        style.setBorderRight(BorderStyle.THIN);
        //设置字体
        style.setFont(font);
        return style;
    }

    /**
     * 头部标题样式
     *
     * @param cellStyle 单元格样式
     * @param font      字体
     * @param fontSize  字体大小
     * @return {@link CellStyle}
     */
    public static CellStyle headerStyle(CellStyle cellStyle, Font font, int fontSize) {
        font.setBold(true);
        font.setFontHeightInPoints((short) fontSize);
        cellStyle.setFont(font);
        czSpCenter(cellStyle);
        return border(cellStyle);
    }

    /**
     * 无边框
     *
     * @param cellStyle 单元格样式
     * @return {@link CellStyle}
     */
    public static CellStyle borderNone(CellStyle cellStyle) {
        //下边框
        cellStyle.setBorderBottom(BorderStyle.NONE);
        //左边框
        cellStyle.setBorderLeft(BorderStyle.NONE);
        //上边框
        cellStyle.setBorderTop(BorderStyle.NONE);
        //右边框
        cellStyle.setBorderRight(BorderStyle.NONE);
        return czSpCenter(cellStyle);
    }

    /**
     * 上边框
     *
     * @param cellStyle 单元格样式
     * @return {@link CellStyle}
     */
    public static CellStyle borderTop(CellStyle cellStyle) {
        cellStyle.setBorderTop(BorderStyle.THIN);
        return cellStyle;
    }

    /**
     * 上下左右边框,自动换行
     *
     * @param cellStyle 单元格样式
     * @return {@link CellStyle}
     */
    public static CellStyle border(CellStyle cellStyle) {
        //下边框
        cellStyle.setBorderBottom(BorderStyle.THIN);
        //左边框
        cellStyle.setBorderLeft(BorderStyle.THIN);
        //上边框
        cellStyle.setBorderTop(BorderStyle.THIN);
        //右边框
        cellStyle.setBorderRight(BorderStyle.THIN);
        //自动换行
        cellStyle.setWrapText(true);
        return cellStyle;
    }


    /**
     * 垂直居中，和水平居中
     *
     * @param cellStyle 单元格样式
     * @return {@link CellStyle}
     */
    public static CellStyle czSpCenter(CellStyle cellStyle) {
        //垂直居中
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        //水平居中
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        return cellStyle;
    }

    /**
     * 左对齐
     *
     * @param cellStyle 单元格样式
     * @return {@link CellStyle}
     */
    public static CellStyle leftAlign(CellStyle cellStyle) {
        //垂直居中
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        //水平居中
        cellStyle.setAlignment(HorizontalAlignment.LEFT);
        return cellStyle;
    }

    /**
     * 右对齐
     *
     * @param cellStyle 单元格样式
     * @return {@link CellStyle}
     */
    public static CellStyle rightAlign(CellStyle cellStyle) {
        //垂直居中
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        //水平居中
        cellStyle.setAlignment(HorizontalAlignment.RIGHT);
        return cellStyle;
    }

    /**
     * 如果是数字类型，去除末尾的0；如果字符串为null，替换为空
     *
     * @param o o
     * @return {@link String}
     */
    public static String changeExcelValue(Object o) {
        if (o instanceof BigDecimal) {
            return NumberUtil.toStr(Convert.toBigDecimal(o));
        }
        return Convert.toStr(o, "");
    }

    /**
     * 输出excel
     *
     * @param response    响应
     * @param excelWriter 工作簿
     * @param fileName    文件名称
     */
    public static void outputExcel(HttpServletResponse response, ExcelWriter excelWriter, String fileName) {
        OutputStream ouputStream = null;
        try {
            ouputStream = response.getOutputStream();
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition", "attachment;filename=" + new String(fileName.getBytes(), "iso-8859-1") + ".xlsx");
            response.setHeader("Set-Cookie", "fileDownload=true;path=/");
            excelWriter.flush(ouputStream);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            try {
                ouputStream.flush();
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
            try {
                ouputStream.close();
            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }
    }
}
